1. Introducción

El objetivo de esta práctica es hacer un análisis de diferentes modelos predictivos para poder determinar la polaridad de un Tweet. En concreto nos interesará saber si un determinado Tweet es positivo o no en base a las palabras que lo componen. La variable dependiente a predecir será una variable cualitativa (POSITIVO) y que se tratará como un factor de dos posibles valores (V/F). Las variables independientes serán el conjunto de palabras que forman los diferentes Tweets que utilizaremos. Indicar que los Tweets que se analizarán serán en español y que no existen paquetes en R que puedan ayudarnos a obtener la polaridad de un Tweet.

Twitter se ha convertido en una red social muy importante y de un gran volumen de información donde el análisis de los textos de los Tweets que se escriben puede ofrecernos una información de un gran valor. Obtener la polaridad (positivo/negativo) o los sentimientos de los Tweets es una tarea compleja debido a las características del lenguaje natural y a la propia forma de un Tweet con un lenguaje denso de 140 carácteres, que puede contener abreviaciones, palabras en argot, ironías, hashtags o menciones a otros usuarios entre otros elementos. Todas estas características dificultan un correcto análisis y debido a esto el análisis de sentimiento del lenguaje natural es un tema de mucha actualidad.

En esta práctica analizaremos y compararemos diferentes modelos para escoger aquel que nos ofrezca unos resultados de predicción mejores, es decir unos errores de clasificación de Tweets positivos menores.

2. Tratamiento de la Información

En este apartado estudiaremos la naturaleza de los datos a tratar para poder extraer las características que nos permitan crear los modelos predictivos.

2.1. Análisis Descriptivo

Nuestro conjunto de datos está formado por un total de 11.290 tweets que ya han sido categorizados. Los niveles de clasificación utilizados son:

  • Muy Positivos (P+)
  • Positivos (P)
  • Neutros (NEU)
  • Negativos (N)
  • Muy Negativos (N+)
  • Sin Clasificación (NONE)

Los ficheros utilizados se han obtenido de la siguiente dirección. Y pueden descargarse de aquí

En concreto los ficheros utilizados son los siguientes:

- general-train-tagged
- intertass-train-tagged
- intertaas-development-tagged
- socialtv-train-tagged
- stompol-train-tagged

Son ficheros con Tweets de diferentes ámbitos: general, vida social, política y categorizados de un manera subjetiva por lo que podríamos encontrar Tweets que para una persona fuesen positivos y para otra negativos.

El primer paso a realizar es fusionar todos los ficheros a tratar y seleccionar las columnas que nos interesan para poder realizar nuestros modelos predictivos. En concreto nos interesa la columna “TEXTO” y la columna “POLARIDAD”. A continuación se puede ver la estructura del DataFrame resultante.

Se puede ver también el Texto de varios Tweets y podemos fijarnos como ya podíamos imaginar que el texto puede tener elementos que son Hashtags(#), menciones a otros usuarios (@) o otros elementos propios de Twitter como es la indicación para indicar que un Tweet es un ReTweet de otro (RT). Para centrarnos solo en el contenido propio del Tweet y para que estos elementos no puedan interferir en las predicciones de nuestros modelos eliminaremos estos elementos. Este proceso se realizará a posteriori, primero vamos a anlizar los Tweets originales sin modificar.

## 'data.frame':    11290 obs. of  2 variables:
##  $ Texto    : chr  "Salgo de #VeoTV , que día más largoooooo..." "@PauladeLasHeras No te libraras de ayudar me/nos. Besos y gracias" "@marodriguezb Gracias MAR" "Off pensando en el regalito Sinde, la que se va de la SGAE cuando se van sus corruptos. Intento no sacar conclu"| __truncated__ ...
##  $ Polaridad: chr  "NONE" "NEU" "P" "N+" ...

La distribución de los Tweets entre su polaridad es la siguiente:

Para simplificar fusionaremos los Tweets “Muy Positivos” y “Positivos” y los “Muy Negativos” y “Negativos” para obtener un total de 4 niveles de polaridad. La nueva distribución es la siguiente. Podemos ver como el número de Tweets “Positivos” es ligeramente superior al número de Tweets “Negativos” lo que nos indica una distrubición bastante equitativa.

Queremos ver a continuación la distribución del contenido de las palabras que forman los Tweets organizado según la polaridad del Tweet al que pertenecen. Para ello construimos els siguiente wordcloud.

Podemos ver como el wordcloud nos ilustra de una manera gráfica como palabras como “gracias”, “feliz”, “bien” o “mejor” están clasificadas en Tweets Positivos y como palabras como “violencia”, “mala”, “deuda” o “impuestos” está clasificadas como pertenecientes a Tweets Negativos. Esto nos indica que una predicción basada en el conjunto de palabras que forman un Tweet puede ofrecer buenos resultados.

Nos fijamos también, que se encuentran palabras que no nos apartarán valor para la predicción como por ejemplo: “http”, números, o preposiciones o artículos. Como ya hemos comentado dedicaremos un apartado de esta práctica a la limpieza de los Tweets para trabajar solo con aquella información que nos pueda aportar valor.

A continuación y dado que queremos precedir aquellos Tweets que sean positivos crearemos nuestra variable dependiente generando una nueva variable factor de aquellos Tweets que sean positivos.

## 'data.frame':    11290 obs. of  3 variables:
##  $ Texto    : chr  "Salgo de #VeoTV , que día más largoooooo..." "@PauladeLasHeras No te libraras de ayudar me/nos. Besos y gracias" "@marodriguezb Gracias MAR" "Off pensando en el regalito Sinde, la que se va de la SGAE cuando se van sus corruptos. Intento no sacar conclu"| __truncated__ ...
##  $ Polaridad: Factor w/ 4 levels "N","NEU","NONE",..: 3 2 4 1 4 3 4 3 4 4 ...
##  $ Positivo : Factor w/ 2 levels "FALSE","TRUE": 1 1 2 1 2 1 2 1 2 2 ...

2.2 Training, Validación y Test

A continuación vamos a dividir nuestros datos en Training, Validación y Test. Hacemos esta distribución para poder entrenar nuestros modelos en el conjunto de Training, validarlos en el conjunto de Validación y una vez seleccionado el mejor modelo, obtener el resultado final sobre el conjunto de Test. La división que realizaremos del total de los Tweets será la siguiente:

  • Training (60%)
  • Validación (20%)
  • Test (20%)
## [1] 6775    3
## [1] 2258    3
## [1] 2257    3

2.3 Preparando el Corpus

En términos de procesamiento de lenguaje, un Corpus es un conjunto grande y estructurado de textos. Se utilizan para realizar análisis estadísticos, verificar ocurrencias o validar reglas lingüísticas dentro de un ámbito lingüístico específico. En nuestro caso particular, estamos hablando de la colección de fragmentos de texto que forman el conjunto de todos los Tweets.

Trabajar con un Corpus implica el uso de técnicas de procesamiento de lenguaje natural y como tal la extracción de características para determinar cómo influyen las asociaciones de palabras en la polaridad de un Tweet puede ser compleja y sigue siendo hoy en día un ámbito de estudio muy actual.

En esta práctica y dado que el objetivo es más bien la comparación de modelos predictivos que una extracción de características óptima utilizaremos el concepto de “Bolsa de Palabras.” Los requisitos de un clasificador de “Bolsa de Palabras”" son mínimos ya que solo necesitamos contar las palabras, por lo que el proceso se reduce en hacer una cierta simplificación y unificación de los términos y luego contarlos.

Entonces, en esta sección, procesaremos los textos que forman nuestros Tweets para poder quedarnos con la información que aporta valor al Tweet y posteriormente crearemos un corpus para poder extraer las frecuencias de las palabras.

Por ejemplo, el contenido de los dos primeros documentos se ve así.

## [1] "Off pensando en el regalito Sinde, la que se va de la SGAE cuando se van sus corruptos. Intento no sacar conclusiones (lo intento)"
## [1] "Conozco a alguien q es adicto al drama! Ja ja ja te suena d algo!"

2.4. Limpieza de Datos

Para poder utilizar el Corpus correctamente necesitamos simplificar y transformar su contenido a un formato estándard para todos los Tweets. Los procesos de limpieza y estandarización que se han realizada han sido los siguientes:

  • Poner todo en minúsculas.
  • Eliminar referencias a URLs.
  • Eliminar Hashtags.
  • Eliminar indicadores de ReTweet.
  • Eliminar menciones a otros usuarios.
  • Eliminar números y espacios en blanco.
  • Eliminar signos de puntuación
  • Eliminar StopWords en Español que no nos proporcionan información relevante para nuestra clasificación (preposiciones, artículos, …)

Una vez realizado este proceso las dos primeras entradas se veen así.

## [1] "off pensando regalito sinde va sgae van corruptos intento no sacar conclusiones intento"
## [1] "conozco alguien adicto drama ja ja ja suena "

2.4 Feature Engineering

Para encontrar las características de nuestro clasificador, vamos a poner este Corpus en la forma de una matriz de documentos (DocumentTermMatrix). Una matriz de documentos es una matriz numérica que contiene una columna para cada palabra diferente en todo nuestro Corpus y una fila para cada documento. Una celda dada es igual a la frecuencia en un documento para un término dado.

De esta manera usamos nuestras entradas de texto para construir frecuencias de términos. Terminamos con las mismas entradas en nuestro conjunto de datos pero, en lugar de tenerlas definidas por un texto completo, ahora están definidas por una serie de conteos de las palabras más frecuentes en todo nuestro corpus. Estas van a ser las características que utilizaremos para entrenar a nuestro clasificador.

## <<DocumentTermMatrix (documents: 9033, terms: 18804)>>
## Non-/sparse entries: 65705/169790827
## Sparsity           : 100%
## Maximal term length: 52
## Weighting          : term frequency (tf)

Un ejemplo de muestra de nuestra matriz es el siguiente:

## <<DocumentTermMatrix (documents: 100, terms: 5)>>
## Non-/sparse entries: 5/495
## Sparsity           : 99%
## Maximal term length: 12
## Weighting          : term frequency (tf)
## Sample             :
##     Terms
## Docs conclusiones corruptos intento off pensando
##   1             1         1       2   1        1
##   10            0         0       0   0        0
##   2             0         0       0   0        0
##   3             0         0       0   0        0
##   4             0         0       0   0        0
##   5             0         0       0   0        0
##   6             0         0       0   0        0
##   7             0         0       0   0        0
##   8             0         0       0   0        0
##   9             0         0       0   0        0

Dado que la matriz contiene un total de 18.829 términos diferentes y un valor de sparsity de 100% vamos a estudiar las frecuencias de los términos y solo nos quedaremos con aquellos más frecuentes para descartar los menos frecuentes y que no nos aportan valor. A continuación podemos ver la distribución de frecuencias de términos en nuestra matriz.

## (Intercept)           x 
##   8.0888519  -0.8556473

Como era de esperar hay pocos téminos con una alta frecuencia y muchos términos con frecuencias bajas.

Obtendremos a continuación una lista de los 20 términos más frecuentes

Para obtener una representación más ámplia de los términos más frecuentes generamos a continuación un WordCloud donde el tamaño y el color de los términos nos indica la cantidad de apariciones en los textos.

Si el objtetivo de esta práctica fuese optimizar la extracción de características del lenguaje natural de los Tweets para poder optimizar también nuestro clasificador podríamos continuar con el análisis de la información e incorporar al modelo no solamente palabras independientes unas de otras (unigramas) sino también de qué manera influye la combinación de dos o más palabras en la predicción de la polaridad (bigramas, n-gramas). Un ejemplo es la búsqueda de asociaciones entre las palabras “madrid” o “gracias”.

findAssocs(tdm, "madrid", 0.2)
## $madrid
##    real    hala   ¡hala    copa campeon 
##    0.48    0.42    0.21    0.20    0.20
findAssocs(tdm, "gracias", 0.2)
## $gracias
## muchas 
##   0.23

Incorporando esta información a nuestro modelo podríamos optimizar las predicciones de nuestros modelos ya que consideraríamos combinaciones de palabras en lugar de solo palabras independientes. Dado que no se trata del objetivo de esta práctica nos centraremos en la generación de los modelos predictivos para palabras independientes.

Dado que algunos términos son más importantes que otros, queremos eliminar aquellos que no lo son tanto. Podemos usar para ello la función removeSparseTerms del paquete “tm” donde pasamos la matriz y un número que proporciona la dispersión máxima permitida para un término en nuestro corpus.

Por ejemplo, si queremos términos que aparezcan en al menos el 1% de los documentos, podemos hacer lo siguiente.

## <<DocumentTermMatrix (documents: 9033, terms: 60)>>
## Non-/sparse entries: 9851/532129
## Sparsity           : 98%
## Maximal term length: 9
## Weighting          : term frequency (tf)

Terminamos con solo 60 términos.

Ahora queremos convertir esta matriz en dos DataFrames diferentes, uno de training y otro de validación que podamos usar para entrenar y validar nuestros modelos.

De esta manera obtenemos un DataFrame para nuestros valores de entrenamiento formado por 6775 muestras y 61 columnas. 60 variables independientes y una variable dependiente.

## [1] 6775   61

De igual manera para nuestro conjunto de validación

## [1] 2258   61

3. Modelos de Clasificación

En este apartado estudiaremos y compararemos los diferentes modelos de clasificación que nos permitirán obtener predicciones sobre la polaridad de un Tweet concreto. Para poder compararlos nos basaremos en el error de clasificación que habremos obtenido después de entrenar nuestros modelos en el conjunto de datos de Training y realizar las predicciones en el conjunto de datos de Validación realizando Validación Cruzada para aquellos modelos que necesiten ajustar algunos parámetros. Guardaremos el valor obtenido para cada uno de los modelos y finalmente los comparemos para realizar las predicciones en los datos de Test.

3.1. Error Mínimo de Clasificación

Según la naturaleza de los datos podría suceder que al intentar predecir los Tweets positivos, la gran mayoría de nuestros Tweets ya fuesen clasificados como positivos por lo que nuestro clasificador no sería realista. Hemos visto como la proporción entre Tweets positivos y negativos era más o menos equitativa pero aun así necesitamos saber el error mínimo de clasificación para saber a partir de que predicciones de clasificación de nuestros modelos se obtienen mejores valores que el simple hecho de obtenerlos al azar.

A continuación obtendremos el error mínimo de clasificación por encima del cual al aplicar los algoritmos de este ejercicio podremos decir que obtenemos una mejor clasificación que simplemente generar un valor aleatorio.

## 
## FALSE  TRUE 
##  6996  4294
##     FALSE 
## 0.6196634

3.2. Regresión Logística

El algoritmo de clasificación de regresión logística nos permite predecir la probabilidad de una variable dependiente categórica siendo el resultado una variable binaria que contiene valores de 0 ó 1. Dado que queremos predecir si un Tweet va a ser positivo o no (2 clases) puede que este método nos ofrezca buenos resultados. Esperamos que en nuestro caso también pueda explicar la relación entre la variable dependiente y las variables independientes.



## 
## Call:
## glm(formula = Positivo ~ ., family = "binomial", data = train_data_words_df)
## 
## Deviance Residuals: 
##     Min       1Q   Median       3Q      Max  
## -2.7150  -0.8883  -0.7435   1.1980   2.2883  
## 
## Coefficients:
##              Estimate Std. Error z value Pr(>|z|)    
## (Intercept) -0.726188   0.037120 -19.563  < 2e-16 ***
## día          0.555875   0.169339   3.283 0.001028 ** 
## grande       1.524791   0.279218   5.461 4.74e-08 ***
## hoy          0.378423   0.123300   3.069 0.002147 ** 
## ser          0.354333   0.177302   1.998 0.045665 *  
## congreso    -0.196418   0.246052  -0.798 0.424708    
## gracias      2.435894   0.206704  11.784  < 2e-16 ***
## X.           0.381423   0.130299   2.927 0.003419 ** 
## días        -0.478245   0.269414  -1.775 0.075876 .  
## gran         1.262177   0.214054   5.897 3.71e-09 ***
## ahora       -0.467413   0.180482  -2.590 0.009603 ** 
## mundo       -0.422597   0.288439  -1.465 0.142889    
## sin         -0.695124   0.184752  -3.762 0.000168 ***
## años         0.333831   0.220285   1.515 0.129657    
## dos         -0.139447   0.212072  -0.658 0.510830    
## gobierno    -0.255077   0.174743  -1.460 0.144367    
## puede       -0.687185   0.259812  -2.645 0.008171 ** 
## siempre      0.209877   0.229206   0.916 0.359840    
## copa         0.190187   0.201151   0.945 0.344408    
## españa      -0.287152   0.197914  -1.451 0.146810    
## madrid       0.763203   0.130439   5.851 4.89e-09 ***
## menos       -0.130037   0.223432  -0.582 0.560568    
## parece      -0.651801   0.286663  -2.274 0.022981 *  
## hace        -0.346985   0.222657  -1.558 0.119143    
## bueno        0.868092   0.222166   3.907 9.33e-05 ***
## equipo       1.042081   0.296139   3.519 0.000433 ***
## ver          0.228632   0.168881   1.354 0.175798    
## buenos       1.082587   0.265294   4.081 4.49e-05 ***
## nuevo        0.719198   0.251380   2.861 0.004223 ** 
## mañana      -0.221848   0.179666  -1.235 0.216912    
## noche        0.226720   0.238247   0.952 0.341291    
## así         -0.176160   0.263215  -0.669 0.503329    
## aquí         0.529254   0.232192   2.279 0.022644 *  
## tan          0.001823   0.223656   0.008 0.993495    
## solo         0.074434   0.242633   0.307 0.759012    
## psoe        -0.534968   0.233666  -2.289 0.022053 *  
## rajoy       -0.300485   0.166696  -1.803 0.071452 .  
## mejor        1.213436   0.185663   6.536 6.33e-11 ***
## vamos        1.149612   0.238887   4.812 1.49e-06 ***
## mas          0.426986   0.158933   2.687 0.007219 ** 
## rey          0.277823   0.244860   1.135 0.256534    
## año          0.307218   0.210774   1.458 0.144959    
## dice        -0.837271   0.250646  -3.340 0.000836 ***
## feliz        1.706812   0.318722   5.355 8.55e-08 ***
## vez         -0.418242   0.260967  -1.603 0.109009    
## gente        0.191097   0.245659   0.778 0.436631    
## barcelona   -0.909891   0.237187  -3.836 0.000125 ***
## vía         -0.085081   0.193301  -0.440 0.659830    
## bien         0.999057   0.197474   5.059 4.21e-07 ***
## hacer       -0.179678   0.211208  -0.851 0.394928    
## real         0.040383   0.218293   0.185 0.853234    
## buenas       1.598432   0.273747   5.839 5.25e-09 ***
## pues        -0.346922   0.278031  -1.248 0.212110    
## portada     -1.816236   0.409661  -4.434 9.27e-06 ***
## partido      0.507772   0.211765   2.398 0.016494 *  
## nada        -0.058052   0.212796  -0.273 0.785002    
## contra      -0.560493   0.248179  -2.258 0.023919 *  
## barça       -0.632985   0.213761  -2.961 0.003065 ** 
## ramos       -0.591187   0.270672  -2.184 0.028951 *  
## messi       -1.165089   0.240890  -4.837 1.32e-06 ***
## bale         1.096622   0.218517   5.018 5.21e-07 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 9000.5  on 6774  degrees of freedom
## Residual deviance: 8093.0  on 6714  degrees of freedom
## AIC: 8215
## 
## Number of Fisher Scoring iterations: 4

La función de summary nos da una visión realmente buena del modelo que acabamos de construir. La sección de coeficientes enumera todas las variables de entrada utilizadas en el modelo.

Los arteriscos nos ofrecen la importancia de cada una de las variables en términos estadísticos. Así por ejemplo tenemos que el término “gracias” tiene un alto nivel significativo y un valor positivo en la columna “Estimate”. Por lo que es muy probable que un Tweet con esta palabra sea clasificado como positivo.

Ahora vamos a utilizar el modelo para una predicción en los datos de Validación. Utilizaremos type=“response” para que los resultados de la predicción sean probabilidades y el úmbral de 0.5 para clasificar la respuesta como como negativa (<0.5) o positiva (>0.5).

## [1] 0.6842338

Vemos que con el modelo de regresión logística obtenemos una precisión bastante mejor que la obtenida por el modelo base.

Ahora para comprobar las predicciones realizadas sobre los Tweets utilizados vamos a usar nuestro modelo para etiquetar los Tweets y luego obtener una muestra aleatoria de 5 Tweets clasificados como positivos.

## [1] "'Chico & Rita', premio europeo a la mejor cinta de animación http://t.co/FF7giIse"                                                        
## [2] "Buenos días. El hastag debería ser #cincotuiteros, porque yo soy uno de ellos. #cuatrotuiteros"                                           
## [3] "Este tema os dejo hoy amig@s. Sergio Dalma y Rafita (que será de mi ). Buenas noches. Bs.  http://t.co/p5TW8rKl"                          
## [4] "Shakira ganó ayer 2 Premios 40: Artista latina más importante e influyente en el mundo y Mejor Artista Int. en Lengua Española  ShakiraHQ"
## [5] "Éste es el \"nuevo\" y fantasmagórico hospital de Toledo… Varios años después (vea las fotos) - http://t.co/RPgYvq99"

A continuación una muestra aleatoria de 5 Tweets clasificados como negativos:

## [1] "Bdías. EM no se ira de puente. Si vosotros os vais no dejeis de llevar la tableta o el PC y desde luego Orbyt. De momento no digo más."
## [2] "Así me gusta, Mónica “@moniromaba: @pedroj_ramirez. A la orden jefe. Cualquiera te va a discutir. Ipad+orbyt+trabajo.”"                
## [3] "Durante la campańa, Cospedal decía lo que oía en casa, ahora ya hace lo que oye en casa. http://t.co/caqPmxJM"                         
## [4] "En el Espolón, conmemorando el Día de la Discapacidad http://t.co/52olz4vl"                                                            
## [5] "Descansando 2 http://t.co/1legIDgw"

– Efecto Marginal

Vamos a calcular ahora los coeficientes de la regresión logística, es decir los efectos marginales, para saber la influencia de cada variable independiente en el resultado de la variable dependiente. Es decir, como cambian las probabilidades de que un Tweet sea positivo debido al cambio de una unidad en las variables independientes.

Cuando los modelos implican una transformación no lineal, los coeficientes generalmente no son interpretables directamente. Esto se debe a que los coeficientes expresan la influencia de cada variable separada sobre la variable dependiente en la escala lineal del resultado, no la escala discreta (o probabilidad) del resultado. Por ejemplo, en una regresión logística, los coeficientes expresan el efecto marginal de cada variable incluida en términos del cambio en las probabilidades de que el evento sea igual a 1 dado el cambio de una unidad en la variable independiente.

Con el fin de expresar el cambio de una manera más intuitiva en la probabilidad predicha de que el resultado es igual a 1, se requiere condicionar todas las demás variables incluidas (es decir, seleccionar un conjunto de valores para todas las variables independientes) y ejecutar ese conjunto de valores a través de la función de logit para convertir los valores en probabilidades haciendo así que el efecto marginal (en términos de probabilidad) de una variable sea una función de todas las demás variables incluidas en el modelo.

En realidad el efecto marginal de una variable dada es la pendiente de la superficie de regresión con respecto a otra variable y nos indica la velocidad a la que la variable dependiente cambia en un punto dado, con respeto a una dimensión concreta y manteniendo constantes todos los valores de las variables.

Es un valor particularmente útil porque es intuitivo, es simplemente una pendiente, y porque puede ser calculado a partir de esencialmente cualquier conjunto de estimaciones de regresión.

##     factor     AME     SE       z      p   lower   upper
##      ahora -0.0960 0.0370 -2.5939 0.0095 -0.1686 -0.0235
##        año  0.0631 0.0433  1.4584 0.1447 -0.0217  0.1480
##       años  0.0686 0.0452  1.5164 0.1294 -0.0201  0.1572
##       aquí  0.1087 0.0476  2.2825 0.0225  0.0154  0.2021
##        así -0.0362 0.0541 -0.6693 0.5033 -0.1422  0.0698
##       bale  0.2253 0.0446  5.0531 0.0000  0.1379  0.3127
##      barça -0.1301 0.0438 -2.9675 0.0030 -0.2160 -0.0442
##  barcelona -0.1869 0.0486 -3.8501 0.0001 -0.2821 -0.0918
##       bien  0.2053 0.0403  5.0949 0.0000  0.1263  0.2842
##     buenas  0.3284 0.0557  5.8940 0.0000  0.2192  0.4376
##      bueno  0.1784 0.0455  3.9242 0.0001  0.0893  0.2674
##     buenos  0.2224 0.0543  4.0992 0.0000  0.1161  0.3288
##   congreso -0.0404 0.0505 -0.7984 0.4246 -0.1394  0.0587
##     contra -0.1152 0.0509 -2.2611 0.0238 -0.2150 -0.0153
##       copa  0.0391 0.0413  0.9457 0.3443 -0.0419  0.1201
##        día  0.1142 0.0347  3.2924 0.0010  0.0462  0.1822
##       días -0.0983 0.0553 -1.7765 0.0756 -0.2067  0.0101
##       dice -0.1720 0.0514 -3.3483 0.0008 -0.2727 -0.0713
##        dos -0.0287 0.0436 -0.6576 0.5108 -0.1140  0.0567
##     equipo  0.2141 0.0606  3.5304 0.0004  0.0952  0.3330
##     españa -0.0590 0.0406 -1.4517 0.1466 -0.1387  0.0207
##      feliz  0.3507 0.0650  5.3949 0.0000  0.2233  0.4781
##      gente  0.0393 0.0505  0.7780 0.4366 -0.0596  0.1382
##   gobierno -0.0524 0.0359 -1.4605 0.1442 -0.1227  0.0179
##    gracias  0.5005 0.0410 12.1988 0.0000  0.4201  0.5809
##       gran  0.2593 0.0436  5.9527 0.0000  0.1739  0.3447
##     grande  0.3133 0.0569  5.5050 0.0000  0.2017  0.4248
##       hace -0.0713 0.0457 -1.5593 0.1189 -0.1609  0.0183
##      hacer -0.0369 0.0434 -0.8509 0.3948 -0.1220  0.0481
##        hoy  0.0778 0.0253  3.0768 0.0021  0.0282  0.1273
##     madrid  0.1568 0.0266  5.9051 0.0000  0.1048  0.2089
##     mañana -0.0456 0.0369 -1.2353 0.2167 -0.1179  0.0267
##        mas  0.0877 0.0326  2.6917 0.0071  0.0238  0.1516
##      mejor  0.2493 0.0377  6.6123 0.0000  0.1754  0.3232
##      menos -0.0267 0.0459 -0.5820 0.5605 -0.1167  0.0633
##      messi -0.2394 0.0492 -4.8621 0.0000 -0.3359 -0.1429
##      mundo -0.0868 0.0592 -1.4659 0.1427 -0.2029  0.0293
##       nada -0.0119 0.0437 -0.2728 0.7850 -0.0976  0.0738
##      noche  0.0466 0.0489  0.9518 0.3412 -0.0493  0.1425
##      nuevo  0.1478 0.0515  2.8674 0.0041  0.0468  0.2488
##     parece -0.1339 0.0588 -2.2765 0.0228 -0.2492 -0.0186
##    partido  0.1043 0.0434  2.4015 0.0163  0.0192  0.1895
##    portada -0.3732 0.0839 -4.4489 0.0000 -0.5376 -0.2088
##       psoe -0.1099 0.0480 -2.2922 0.0219 -0.2039 -0.0159
##      puede -0.1412 0.0533 -2.6493 0.0081 -0.2456 -0.0367
##       pues -0.0713 0.0571 -1.2483 0.2119 -0.1832  0.0406
##      rajoy -0.0617 0.0342 -1.8040 0.0712 -0.1288  0.0053
##      ramos -0.1215 0.0555 -2.1867 0.0288 -0.2303 -0.0126
##       real  0.0083 0.0449  0.1850 0.8532 -0.0796  0.0962
##        rey  0.0571 0.0503  1.1350 0.2564 -0.0415  0.1557
##        ser  0.0728 0.0364  2.0006 0.0454  0.0015  0.1441
##    siempre  0.0431 0.0471  0.9159 0.3597 -0.0492  0.1354
##        sin -0.1428 0.0378 -3.7746 0.0002 -0.2170 -0.0687
##       solo  0.0153 0.0499  0.3068 0.7590 -0.0824  0.1130
##        tan  0.0004 0.0460  0.0082 0.9935 -0.0897  0.0904
##      vamos  0.2362 0.0488  4.8438 0.0000  0.1406  0.3318
##        ver  0.0470 0.0347  1.3544 0.1756 -0.0210  0.1150
##        vez -0.0859 0.0536 -1.6037 0.1088 -0.1910  0.0191
##        vía -0.0175 0.0397 -0.4402 0.6598 -0.0953  0.0604
##         X.  0.0784 0.0267  2.9341 0.0033  0.0260  0.1307

Podemos comprobar como palabras como “gracias”, “grande” o “mejor” tienen un efecto marginal promedio (AME) grande por lo que su presencia influye en que un Tweet sea clasificado como Positivo. En cambio palabras como “contra” o “sin” influyen en que un Tweet sea clasificado como no Positivo.

A continuación ilustraremos como influye la combinación de las palabras “gracias” y “grande” en la predicción de un Tweet Positivo:

## 
## # Predicted probabilities of Positivo 
## # x = gracias 
## 
## # 0
##  x predicted std.error conf.low conf.high
##  0     0.353     0.028    0.340     0.365
##  1     0.862     0.205    0.806     0.903
##  2     0.986     0.411    0.969     0.994
##  3     0.999     0.617    0.996     1.000
## 
## # 1
##  x predicted std.error conf.low conf.high
##  0     0.714     0.278    0.592     0.812
##  1     0.966     0.346    0.935     0.983
##  2     0.997     0.498    0.992     0.999
##  3     1.000     0.679    0.999     1.000
## 
## # 2
##  x predicted std.error conf.low conf.high
##  0     0.920     0.556    0.794     0.972
##  1     0.992     0.595    0.976     0.998
##  2     0.999     0.695    0.997     1.000
##  3     1.000     0.835    1.000     1.000
## 
## Adjusted for:
## *      día = 0.02
## *       hoy = 0.05
## *       ser = 0.02
## *  congreso = 0.01
## *        X. = 0.04
## *     días = 0.02
## *      gran = 0.02
## *     ahora = 0.03
## *     mundo = 0.01
## *       sin = 0.03
## *     años = 0.01
## *       dos = 0.01
## *  gobierno = 0.03
## *     puede = 0.01
## *   siempre = 0.01
## *      copa = 0.03
## *   españa = 0.02
## *    madrid = 0.05
## *     menos = 0.02
## *    parece = 0.01
## *      hace = 0.02
## *     bueno = 0.01
## *    equipo = 0.01
## *       ver = 0.02
## *    buenos = 0.02
## *     nuevo = 0.01
## *   mañana = 0.02
## *     noche = 0.01
## *      así = 0.01
## *     aquí = 0.01
## *       tan = 0.01
## *      solo = 0.01
## *      psoe = 0.02
## *     rajoy = 0.03
## *     mejor = 0.02
## *     vamos = 0.01
## *       mas = 0.03
## *       rey = 0.02
## *      año = 0.01
## *      dice = 0.02
## *     feliz = 0.01
## *       vez = 0.01
## *     gente = 0.01
## * barcelona = 0.02
## *      vía = 0.02
## *      bien = 0.02
## *     hacer = 0.02
## *      real = 0.02
## *    buenas = 0.01
## *      pues = 0.01
## *   portada = 0.01
## *   partido = 0.01
## *      nada = 0.02
## *    contra = 0.01
## *    barça = 0.02
## *     ramos = 0.01
## *     messi = 0.02
## *      bale = 0.02

Y como influye la combinación de las palabras “contra” y “sin” en la predicción de un Tweet Negativo:

## 
## # Predicted probabilities of Positivo 
## # x = contra 
## 
## # 0
##  x predicted std.error conf.low conf.high
##  0     0.383     0.028    0.370     0.396
##  1     0.262     0.247    0.179     0.365
##  2     0.168     0.494    0.071     0.348
## 
## # 1
##  x predicted std.error conf.low conf.high
##  0     0.236     0.183    0.178     0.307
##  1     0.150     0.306    0.088     0.244
##  2     0.092     0.526    0.035     0.221
## 
## # 2
##  x predicted std.error conf.low conf.high
##  0     0.134     0.367    0.070     0.241
##  1     0.081     0.441    0.036     0.173
##  2     0.048     0.615    0.015     0.144
## 
## # 3
##  x predicted std.error conf.low conf.high
##  0     0.072     0.551    0.025     0.185
##  1     0.042     0.603    0.013     0.126
##  2     0.025     0.740    0.006     0.097
## 
## Adjusted for:
## *      día = 0.02
## *    grande = 0.01
## *       hoy = 0.05
## *       ser = 0.02
## *  congreso = 0.01
## *   gracias = 0.04
## *        X. = 0.04
## *     días = 0.02
## *      gran = 0.02
## *     ahora = 0.03
## *     mundo = 0.01
## *     años = 0.01
## *       dos = 0.01
## *  gobierno = 0.03
## *     puede = 0.01
## *   siempre = 0.01
## *      copa = 0.03
## *   españa = 0.02
## *    madrid = 0.05
## *     menos = 0.02
## *    parece = 0.01
## *      hace = 0.02
## *     bueno = 0.01
## *    equipo = 0.01
## *       ver = 0.02
## *    buenos = 0.02
## *     nuevo = 0.01
## *   mañana = 0.02
## *     noche = 0.01
## *      así = 0.01
## *     aquí = 0.01
## *       tan = 0.01
## *      solo = 0.01
## *      psoe = 0.02
## *     rajoy = 0.03
## *     mejor = 0.02
## *     vamos = 0.01
## *       mas = 0.03
## *       rey = 0.02
## *      año = 0.01
## *      dice = 0.02
## *     feliz = 0.01
## *       vez = 0.01
## *     gente = 0.01
## * barcelona = 0.02
## *      vía = 0.02
## *      bien = 0.02
## *     hacer = 0.02
## *      real = 0.02
## *    buenas = 0.01
## *      pues = 0.01
## *   portada = 0.01
## *   partido = 0.01
## *      nada = 0.02
## *    barça = 0.02
## *     ramos = 0.01
## *     messi = 0.02
## *      bale = 0.02



3.3 Linear Discriminant Analysis (LDA)

A partir del teorema de Bayes, LDA estima la probabilidad de que una observación, dado un determinado valor de las variables independientes, pertenezca a una de las clases de la variable cualitativa, P(Y=k|X=x). Una vez obtenida la proabilidad y para realizar la clasificación se asigna la observación a la clase k para la que la probabilidad predicha es mayor.

##                   LD1
## día        0.77742679
## grande     1.93197526
## hoy        0.50416892
## ser        0.43686661
## congreso  -0.26376257
## gracias    2.62241605
## X.         0.49613836
## días      -0.56950976
## gran       1.61125534
## ahora     -0.56100129
## mundo     -0.42241980
## sin       -0.78505991
## años       0.44924242
## dos       -0.16855604
## gobierno  -0.32507926
## puede     -0.81987387
## siempre    0.24652830
## copa       0.25764041
## españa    -0.40520838
## madrid     0.98710081
## menos     -0.17378863
## parece    -0.75139306
## hace      -0.44224122
## bueno      1.21415960
## equipo     1.22210990
## ver        0.27226414
## buenos     1.43318298
## nuevo      0.96380068
## mañana    -0.28264030
## noche      0.27359082
## así       -0.23461807
## aquí       0.65777955
## tan        0.01679831
## solo       0.07357121
## psoe      -0.64255091
## rajoy     -0.38831118
## mejor      1.55695431
## vamos      1.49986144
## mas        0.56759291
## rey        0.36913562
## año        0.35301858
## dice      -0.93320001
## feliz      1.93957580
## vez       -0.49513976
## gente      0.27865262
## barcelona -1.07249516
## vía       -0.11970638
## bien       1.33526202
## hacer     -0.23176064
## real       0.05940026
## buenas     2.14579546
## pues      -0.39262550
## portada   -1.67275533
## partido    0.68580636
## nada      -0.06994662
## contra    -0.68522028
## barça     -0.74676261
## ramos     -0.76698278
## messi     -1.29475740
## bale       1.36757124

Al representar los coeficientes de la función discriminante lineal vemos hay una zona que se solapa. Esta es la zona que incrementará el valor de las tasas de error de clasificación del modelo.

La predicción que se obtiene sobre el conjunto de validación es la siguiente:

## [1] 0.6855624

Vemos como es ligeramente superior a la obtenida por Logit.

3.4. Quadratic Discriminant Analysis (QDA)

El análisis disciminante cuadrático considera que cada clase k tiene su propia matriz de covarianza y, como consecuencia, la función discriminante toma forma cuadrática. Debido a esto genera límites de decisión curvos por lo que puede aplicarse a situaciones en las que la separación entre grupos no es lineal.

## Call:
## qda(Positivo ~ ., data = train_data_words_df)
## 
## Prior probabilities of groups:
##    FALSE     TRUE 
## 0.619631 0.380369 
## 
## Group means:
##              día      grande        hoy        ser    congreso     gracias
## FALSE 0.01667461 0.004525965 0.03978085 0.01929490 0.015245355 0.006669843
## TRUE  0.03531238 0.022118743 0.06053551 0.02793946 0.009701203 0.083042297
##               X.       días        gran      ahora      mundo        sin
## FALSE 0.03501667 0.01595998 0.007860886 0.03049071 0.01071939 0.03215817
## TRUE  0.05549088 0.01901436 0.032984090 0.02017850 0.01164144 0.01668607
##             años        dos   gobierno       puede    siempre       copa
## FALSE 0.01333969 0.01476894 0.03025250 0.016198190 0.01048118 0.02906146
## TRUE  0.01629802 0.01280559 0.01901436 0.009701203 0.01823826 0.03802872
##           españa     madrid      menos      parece       hace       bueno
## FALSE 0.02334445 0.03739876 0.01643640 0.013101477 0.01762744 0.009290138
## TRUE  0.01629802 0.08149010 0.01319364 0.007372914 0.01435778 0.020178502
##            equipo        ver     buenos       nuevo     mañana      noche
## FALSE 0.004764173 0.02143878 0.01191043 0.008099095 0.02334445 0.01000476
## TRUE  0.017462165 0.02832751 0.02483508 0.015521925 0.02134265 0.01474583
##              así        aquí        tan       solo        psoe      rajoy
## FALSE 0.01095760 0.009766556 0.01214864 0.01286327 0.020724154 0.03644593
## TRUE  0.01086535 0.018238262 0.01590997 0.01241754 0.009701203 0.02095460
##            mejor       vamos        mas        rey        año       dice
## FALSE 0.01191043 0.006669843 0.02143878 0.01500715 0.01262506 0.02239162
## TRUE  0.04229724 0.022506791 0.03181995 0.02444703 0.01823826 0.00814901
##             feliz         vez       gente  barcelona        vía       bien
## FALSE 0.003096713 0.013816103 0.009290138 0.01881848 0.02096236 0.01071939
## TRUE  0.024447031 0.009701203 0.012029492 0.01125340 0.01707412 0.02910361
##            hacer       real      buenas        pues     portada    partido
## FALSE 0.01881848 0.01333969 0.005002382 0.010481182 0.016912816 0.01191043
## TRUE  0.01396973 0.03026775 0.019402406 0.009313155 0.002716337 0.01862631
##             nada      contra      barça      ramos       messi        bale
## FALSE 0.01667461 0.017389233 0.02072415 0.01595998 0.024535493 0.008099095
## TRUE  0.01358168 0.008537059 0.01358168 0.01047730 0.009313155 0.028715561

El valor de predicción de QDA en el conjunto de validación es el siguiente:

## [1] 0.6607617

Vemos que el valor obtenido es inferior al obtenido en modelos anteriores.

3.5. Árboles de Clasificación

En el modelo de los árboles de clasificación en cada paso se evalúan todas las variables de entrada y todos los puntos de división posibles y se elige la que tenga mejor resultado. Es decir, dividimos los datos en dos o más conjuntos homogéneos basados en la variable más significativa.

Es muy probable que este modelo no funcione correctamente para nuestros datos ya que los modelos basados en árboles no están diseñados para funcionar con características muy dispersas y tal y como hemos podido ver en el apartado de análisis de datos nuestros datos tienen valores de sparsity muy elevados.

## 
## Classification tree:
## tree(formula = Positivo ~ ., data = train_data_words_df)
## Variables actually used in tree construction:
## [1] "gracias"
## Number of terminal nodes:  2 
## Residual mean deviance:  1.292 = 8750 / 6773 
## Misclassification error rate: 0.3551 = 2406 / 6775
## [1] gracias
## 61 Levels: <leaf> día grande hoy ser congreso gracias X. días ... bale

Si entrenamos un modelo con el modelo de árboles de decisión vemos como sólo nos dectecta 2 nodos terminales siendo el término “gracias” determinante para predecir si un Tweet es Positivo o no. Es un indicador de que la variable “gracias” clasifica casi perfectamente a nuestras muestras y aunque parece correcto, debido a la limitación de este modelo y a la naturaleza de nuestros datos, esto no nos permite contemplar otras posibilidades de combinaciones de términos, por lo que no podría servirnos por ejemplo para clasificar un Tweet que no tenga la palabra “gracias” ya que siempre obtendríamos como resultado que el Tweet es negativo.

Para realizar la predicción, el modelo recorre el árbol en función del valor de sus variables hasta llegar a uno de los nodos terminales. En el caso de clasificación, suele emplearse la clase más frecuente del nodo para decidir qué variable escoger

Indicar que el modelo de Árboles de Clasificación tiende a reducir rápidamente el error de entrenamiento, es decir, el modelo se ajusta muy bien a las observaciones empleadas como entrenamiento. Así se genera overfitting que reduce su capacidad predictiva al aplicarlo a nuevos datos.

Es importante indicar que si no se limitan las divisiones del modelo, éste termina ajustándose perfectamente a las observaciones de entrenamiento creando un nodo terminal por observación. Existen dos estrategias para prevenir el problema de overfitting de los árboles: limitar el tamaño del árbol y el proceso de podado (pruning).

Dado que nuestro modelo sólo ha detecatado 2 nodos terminales es muy probable que no se cumplan las condiciones de overfitting descritas anteriormente y que por lo tanto tampoco sea necesario realizar ningún tipo de limitación del tamaño del árbol o poda.

Vamos a comprobar ahora como funciona el modelo entrenado en los datos de Training y Validación para hacer la predicción y comprobar un posible OverFitting.

## [1] 0.6448708

Vemos como el resultado obtenido no es muy alto. Por lo que nos indica que el modelo no genera OverFitting sobre los datos de Training. Hacemos ahora la predicción sobre los datos de Validación.

## [1] 0.6430469

Efectivamente, obtenemos un valor muy parecido al obtenido con los datos de Training (No Overfitting) pero es de los más bajos obtenidos hasta ahora con todos los modelos aplicados. La limitación de este modelo es que sólo se genera un único árbol y por tanto sólo es capaz de comprobar una combinación de probabilidades que en nuestro caso resulta ser muy limitada.

– Controlar el tamaño del árbol

Hemos comprobado como el modelo no genera overfitting y como por lo tanto, no es neceario realizar ningún tipo de limitación del tamaño del árbol o poda, pero queremos generar un modelo que pueda servirnos para otros conjuntos de datos a los utilizados en esta práctica por lo que realizaremos los procedimientos habituales para obtener los parámetros más óptimos de este modelo.

El tamaño final puede controlarse mediante reglas paran la división de los nodos dependiendo de si se cumplen o no determinadas condiciones. Son las siguientes:

  • Observaciones mínimas para división: define el número mínimo de observaciones que debe tener un nodo para poder ser dividido. Cuanto mayor el valor, menos flexible es el modelo.

  • Observaciones mínimas de nodo terminal: define el número mínimo de observaciones que deben tener los nodos terminales. Su efecto es muy similar al de observaciones mínimas para división.

  • Profundidad máxima del árbol: define la profundidad máxima del árbol, entendiendo por profundidad máxima el número de divisiones de la rama más larga (en sentido descendente) del árbol.

  • Número máximo de nodos terminales: define el número máximo de nodos terminales que puede tener el árbol. Una vez alcanzado el límite, se detienen las divisiones. Su efecto es similar al de controlar la profundidad máxima del árbol.

  • Reducción mínima de error: define la reducción mínima de error que tiene que conseguir una división para que se lleve a cabo.

Todos estos parámetros son lo que se conoce como hiperparámetros porque no se aprenden durante el entrenamiento del modelo. Su valor tiene que ser especificado por el usuario en base a su conocimiento del problema y mediante el uso de validación cruzada.

A pesar de que no tenga sentido para nuestro caso, realizamos Validación Cruzada para podar y obtener el tamaño del árbol con menor error de clasificación

## $size
## [1] 2 1
## 
## $dev
## [1] 2406 2577
## 
## $k
## [1] -Inf  171
## 
## $method
## [1] "misclass"
## 
## attr(,"class")
## [1] "prune"         "tree.sequence"
## [1] 2

Efectivamente el árbol con menor error de clasificación tiene dos nodos terminales.

Realizamos el proceso de Poda indicando el parámetro best obtenido a la función prune.misclass

Y obviamente obtenemos el mismo árbol.

Veremos a continuación como afecta el proceso de poda a los valores de predicción sobre Training y Validación para comprobar el overfitting. (En nuestro caso no variarán de los valores obtenidos anteriormente.)

Para Training:

## [1] 0.6448708

Para Validación:

## [1] 0.6430469

Vemos como obtenemos los mismos valores que los obtenidos anteriormente pero la realización del proceso completo nos permite cambiar nuestro conjunto de datos original y disponer de toda la lógica necesaria para analizar este modelo completamente.

3.6. Bagging

El modelo de los árboles de clasificación sufre también el problema del equilibrio entre sesgo y varianza. Para solucionarlo y encontrar el mejor equilibrio utilizaremos los modelos de Bagging y Boosting.

En Bagging en lugar de crear un modelo de un único árbol se ajustan muchos modelos con diferentes muestras (obtenidas a través de Bootstrapping) de manera paralela formando un “bosque” de tal manera que todos los árboles participan en la realización de una predicción y como valor final se tiene en cuenta la clase más frecuente. De esta manera se usan modelos con poco sesgo pero mucha varianza, pero agregando muchos de estos modelos se consigue reducir la varianza.

En Bagging la forma de obtener las muestas a través de Bootstrapping permite que se pueda estimar el error directamente a través del “Out Of Bag” (OOB) formado por un promedio de un tercio de las muestras usadas. Este tercio que Bootstrapping no ha utilizado para la selección de observaciones puede utilizarse para realizar la predicción y en nuestro caso obtener el “OOB-classification-error”.

A continuación entrenamos el modelo de Bagging con nuestros datos de Training.

## 
## Call:
##  randomForest(formula = Positivo ~ ., data = train_data_words_df) 
##                Type of random forest: classification
##                      Number of trees: 500
## No. of variables tried at each split: 7
## 
##         OOB estimate of  error rate: 31.57%
## Confusion matrix:
##       FALSE TRUE class.error
## FALSE  3803  395  0.09409242
## TRUE   1744  833  0.67675592

Vamos a comprobar si hay “overfitting”. Par ello realizamos la predicción sobre los datos de Training.

## [1] 0.71631

Comprobamos como la precisión en el modelo de clasificación es muy alta. La más alta obtenida hasta el momento por lo que se trata de un indicador de “OverFitting”

Realizemos ahora la predicción en el conjunto de Validación.

## [1] 0.6824624

Vemos como con el modelo de Bagging obtenemos una buena precisión de clasificación. La guardamos para poder compararla con todos los modelos.

3.7. Random Forest

Se trata de uno de los métodos de Bagging más conocidos. Tiene en cuenta la correlación que puede haber entre los múltiples árboles generados ya que si la correlación entre ellos es alta no se podrá conseguir reducir la varianza de una manera notable. Para solucionar este problema Random Forest realiza una selección aleatoria de m predictores antes de evaluar cada división de los árboles para evitar que los predictores influyentes puedan ser seleccionados y así que la correlación entre los árboles generados sea alta.

Tanto Bagging como Random Forest siguen los mismos pasos pero Random Forest realiza un paso adicional de seleccioón de predictores antes de cada división. Se puede decir que Bagging es una generalización de Random Forest para m=p. Este hecho nos indica que tendremos que escoger un m óptimo.

Veamos a continuación la evolución del OOB-Error en función del parámetro m para escoger el óptimo. También realizamos una gráfica comparativa entre el Test-Error y el OOB-Error.

## # A tibble: 1 x 2
##   n_predictores oob_err_rate
##           <int>        <dbl>
## 1             6        0.317

Obtenemos que 6 es el número de predictores óptimo a utilizar. Usaremos este valor para optimizar el tamaño de los nodos terminales.

## # A tibble: 1 x 2
##    size oob_err_rate
##   <int>        <dbl>
## 1    18        0.312

Obtenemos que el número óptimo de observaciones mínimas de los nodos terminales es 18.

Una vez obtenidos estos parámetros los utilizamos para obtener el número de árboles óptimo.

##     oob_err arboles
## 1 0.3151292      78

Obtenemos que el número de árboles óptimo es de 78.

Utilizando todos los parámetros obtenidos generamos el modelo final.

## 
## Call:
##  randomForest(formula = Positivo ~ ., data = train_data_words_df,      mtry = 6, ntree = 78, nodesize = 18, importance = TRUE, norm.votes = TRUE) 
##                Type of random forest: classification
##                      Number of trees: 78
## No. of variables tried at each split: 6
## 
##         OOB estimate of  error rate: 31.76%
## Confusion matrix:
##       FALSE TRUE class.error
## FALSE  3789  409  0.09742735
## TRUE   1743  834  0.67636787

Vamos a realizar ahora la predicción sobre el conjunto de validación utilizando el modelo obtenido a partir de los parámetros óptimos.

## [1] 0.6855624

Guardaremos el valor para compararlo con los otros modelos.

Una vez obtenido el modelo óptimo para el modelo de Random Forest, veamos cuáles son las variables más influyentes del modelo y cómo afectan a la precisión obtenida.

Observamos que las variables formadas por los términos “gracias”, “bale”, “feliz”, “grande”, “mejor” son de las más influyentes. Como la palabra “gracias” destaca encima de todas las demás. Recordemos que este hecho ya fue detectado claramente con el módelo de “Arboles de Clasificación”.

Nos preguntamos ahora qué sucedería si nuestro modelo sólo dependiese de estas variables más influyentes.

## 
## Call:
##  randomForest(formula = Positivo ~ +gracias + bale + feliz + grande +      mejor, data = train_data_words_df, mtry = 6, ntree = 46,      nodesize = 18, importance = TRUE, norm.votes = TRUE) 
##                Type of random forest: classification
##                      Number of trees: 46
## No. of variables tried at each split: 5
## 
##         OOB estimate of  error rate: 33.33%
## Confusion matrix:
##       FALSE TRUE class.error
## FALSE  4064  134  0.03191996
## TRUE   2124  453  0.82421420

Vemos que obtenemos un porcentaje de error mayor que utilizando todas la variables. Dado que queremos conseguir unos valores óptimos optaremos por utilizar todas las variables.

3.8. Boosting

Boosting es como hemos indicado anteriormente otro de los métodos utilizados para poder encontrar el mejor equilibrio entre sesgo y varianza.

Este modelo consiste en ajustar muchos modelos sencillos de manera secuencial y que cada uno de ellos tenga en cuenta los errores del anterior. El valor final se obiene tomando la clase más frecuente, de la misma manera que en Bagging. De esta manera los modelos que se usan en Boosting tienen muy poca varianza pero mucho sesgo y considerando muchos de estos modelos se consigue reducir el sesgo.

Utilizamos el paquete “caret” con un grid de diferentes valores y Validación Cruzada para econtrar los siguientes parámetros óptimos:

  • interaction.depth: es el número de divisiones que tiene el árbol. El rango de valores que utilizaremos será: 1, 5 y 10

  • n.trees: se trata del número de modelos que se generan. Al aumentar este valor reducimos el error de entrenamiento pero generando “overfitting”. Los valores que utilizaremos para nuestro grid serán: 50, 100, 200

  • shrinkage: es el learning rate y dado que en Boosting los modelos dependen de los valores anteriores, controla la influencia de cada uno de ellos sobre el total. La idea en referencia en este parámetro es optar por valores pequeños ya qu es preferible un modelo con muchos pasos, pero cada uno de ellos con una menor influencia que por pocos pasos. Los valores utilizados son: 0.005, 0.05, 0.5

  • n.minobsinnode: es el número de observaciones mínimo para poder ser dividido. Los valores utilizados son: 1, 10, 20

Obtenemos que la mejor combinación de parámetros es la siguiente:

##    n.trees interaction.depth shrinkage n.minobsinnode
## 70      50                 5       0.5             20

El mejor valor de precisión obtenido a través de Validación Cruzada es el siguiente:

## [1] 0.6879732

Si realizamos la predicción sobre el conjunto de validación obtenemos el siguiente valor:

## [1] 0.6917626

Guardaremos este valor para poder compararlo.

3.9. Extreme Gradient Boosting

XGBoost es una de las implementaciones del concepto Gradient Boosting y utiliza la misma filosofia de clasificadores débiles que aportan la información de los errores a los modelos posteriores. Pero lo que hace que XGBoost sea único es que utiliza una formalización de modelo más regularizada para controlar el “overfitting”, lo que le da un mejor rendimiento. La implementación de XGBoost ofrece varias características avanzadas para el ajuste de modelos y admite un ajuste detallado y la adición de parámetros de regularización.

Para aplicar el modelo de “Extreme Gradient Boosting” utilizaremos el paquete “caret” y a través de TuneGrid y TrainControl de Validación Cruzada de 5 folds ajustaremos los siguientes parámetros:

  • nrounds: El número máximo de iteraciones (número de árboles en el modelo final). Los valores utilizados son 100,350

  • colsample_bytree: El número de características, expresadas como una proporción, a muestrear cuando se construye un árbol. Es el número de variables aleatorias que se le proporciona a cada nuevo árbol. El valor predeterminado es 1 (100% de las características). El valor que utilizaremos es de 0.75.

  • min_child_weight: El peso mínimo en los árboles que están siendo generados. El valor predeterminado es 1. Los valores que utilizamos son 0, 0.5, 1

  • eta: Tasa de aprendizaje, que es la contribución de cada árbol a la solución. El valor predeterminado es 0.3. Los valores que hemos utilizado son 0.05, 0.1, 0.5.

  • gama: Reducción de pérdida mínima requerida para hacer otra partición en un árbol. Utilizamos 0.01 como valor en nuestro Grid.

  • subsample: Relación de observaciones de datos. El valor predeterminado es 1 (100%). Utilizaremos 0.5.

  • max_depth: Máxima profundidad de los árboles individuales. Utiliaremos los valores 4,6,10.

## + Fold1: eta=0.05, max_depth= 4, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold1: eta=0.05, max_depth= 4, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold1: eta=0.05, max_depth= 6, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold1: eta=0.05, max_depth= 6, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold1: eta=0.05, max_depth=10, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold1: eta=0.05, max_depth=10, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold1: eta=0.10, max_depth= 4, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold1: eta=0.10, max_depth= 4, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold1: eta=0.10, max_depth= 6, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold1: eta=0.10, max_depth= 6, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold1: eta=0.10, max_depth=10, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold1: eta=0.10, max_depth=10, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold1: eta=0.50, max_depth= 4, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold1: eta=0.50, max_depth= 4, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold1: eta=0.50, max_depth= 6, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold1: eta=0.50, max_depth= 6, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold1: eta=0.50, max_depth=10, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold1: eta=0.50, max_depth=10, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold2: eta=0.05, max_depth= 4, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold2: eta=0.05, max_depth= 4, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold2: eta=0.05, max_depth= 6, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold2: eta=0.05, max_depth= 6, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold2: eta=0.05, max_depth=10, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold2: eta=0.05, max_depth=10, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold2: eta=0.10, max_depth= 4, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold2: eta=0.10, max_depth= 4, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold2: eta=0.10, max_depth= 6, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold2: eta=0.10, max_depth= 6, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold2: eta=0.10, max_depth=10, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold2: eta=0.10, max_depth=10, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold2: eta=0.50, max_depth= 4, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold2: eta=0.50, max_depth= 4, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold2: eta=0.50, max_depth= 6, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold2: eta=0.50, max_depth= 6, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold2: eta=0.50, max_depth=10, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold2: eta=0.50, max_depth=10, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold3: eta=0.05, max_depth= 4, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold3: eta=0.05, max_depth= 4, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold3: eta=0.05, max_depth= 6, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold3: eta=0.05, max_depth= 6, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold3: eta=0.05, max_depth=10, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold3: eta=0.05, max_depth=10, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold3: eta=0.10, max_depth= 4, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold3: eta=0.10, max_depth= 4, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold3: eta=0.10, max_depth= 6, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold3: eta=0.10, max_depth= 6, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold3: eta=0.10, max_depth=10, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold3: eta=0.10, max_depth=10, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold3: eta=0.50, max_depth= 4, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold3: eta=0.50, max_depth= 4, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold3: eta=0.50, max_depth= 6, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold3: eta=0.50, max_depth= 6, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold3: eta=0.50, max_depth=10, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold3: eta=0.50, max_depth=10, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold4: eta=0.05, max_depth= 4, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold4: eta=0.05, max_depth= 4, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold4: eta=0.05, max_depth= 6, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold4: eta=0.05, max_depth= 6, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold4: eta=0.05, max_depth=10, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold4: eta=0.05, max_depth=10, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold4: eta=0.10, max_depth= 4, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold4: eta=0.10, max_depth= 4, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold4: eta=0.10, max_depth= 6, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold4: eta=0.10, max_depth= 6, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold4: eta=0.10, max_depth=10, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold4: eta=0.10, max_depth=10, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold4: eta=0.50, max_depth= 4, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold4: eta=0.50, max_depth= 4, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold4: eta=0.50, max_depth= 6, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold4: eta=0.50, max_depth= 6, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold4: eta=0.50, max_depth=10, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold4: eta=0.50, max_depth=10, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold5: eta=0.05, max_depth= 4, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold5: eta=0.05, max_depth= 4, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold5: eta=0.05, max_depth= 6, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold5: eta=0.05, max_depth= 6, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold5: eta=0.05, max_depth=10, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold5: eta=0.05, max_depth=10, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold5: eta=0.10, max_depth= 4, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold5: eta=0.10, max_depth= 4, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold5: eta=0.10, max_depth= 6, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold5: eta=0.10, max_depth= 6, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold5: eta=0.10, max_depth=10, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold5: eta=0.10, max_depth=10, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold5: eta=0.50, max_depth= 4, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold5: eta=0.50, max_depth= 4, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold5: eta=0.50, max_depth= 6, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold5: eta=0.50, max_depth= 6, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## + Fold5: eta=0.50, max_depth=10, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## - Fold5: eta=0.50, max_depth=10, gamma=0.01, colsample_bytree=0.75, min_child_weight=0, subsample=0.5, nrounds=350 
## Aggregating results
## Selecting tuning parameters
## Fitting nrounds = 100, max_depth = 4, eta = 0.05, gamma = 0.01, colsample_bytree = 0.75, min_child_weight = 0, subsample = 0.5 on full training set

A continuación obtendremos el modelo final que con los parámetros indicados ofrece mejores resultados.

## ##### xgb.Booster
## raw: 94.3 Kb 
## call:
##   xgboost::xgb.train(params = list(eta = param$eta, max_depth = param$max_depth, 
##     gamma = param$gamma, colsample_bytree = param$colsample_bytree, 
##     min_child_weight = param$min_child_weight, subsample = param$subsample), 
##     data = x, nrounds = param$nrounds, verbose = FALSE, objective = "binary:logistic")
## params (as set within xgb.train):
##   eta = "0.05", max_depth = "4", gamma = "0.01", colsample_bytree = "0.75", min_child_weight = "0", subsample = "0.5", objective = "binary:logistic", silent = "1"
## xgb.attributes:
##   niter
## # of features: 61 
## niter: 100
## nfeatures : 61 
## xNames : Positivo día grande hoy ser congreso gracias X. días gran ahora mundo sin años dos gobierno puede siempre copa españa madrid menos parece hace bueno equipo ver buenos nuevo mañana noche así aquí tan solo psoe rajoy mejor vamos mas rey año dice feliz vez gente barcelona vía bien hacer real buenas pues portada partido nada contra barça ramos messi bale 
## problemType : Classification 
## tuneValue :
##    nrounds max_depth  eta gamma colsample_bytree min_child_weight subsample
## 1     100         4 0.05  0.01             0.75                0       0.5
## obsLevels : No Yes 
## param :
##  $verbose
## [1] FALSE

Realizamos la predicción sobre el conjunto de validación.

## [1] 0.6789194

Vemos como a pesar de la potencia de este algoritmo parece que no obtenemos el valor más alto de precisión. Guardaremos el valor para compararlo con los otros modelos

Otro método para medir el rendimiento en la clasificación binaria además de la precisión es el método ROC. A diferencia de la precisión, el análisis ROC utiliza la tasa de verdaderos positivos (TPR) y la tasa de falsos positivos (FPR). TPR es la proporción positiva clasificada correctamente (TP / P) y la tasa de falsos positivos (FPR) se calcula por 1-TNR (TN / N). La región ROC muestra la tasa de verdaderos postivos (TPR) contra la tasa de falsos positivos (FPR).

##      Model      Area      p.value binorm.area
## 1 Model  1 0.6533833 3.149953e-39          NA

Como podemos ver el modelo puede diferenciar entre Tweets Positivos y no Positivos pero si nos fijamos en el Area Under Curve (AUC) vemos que el valor obtenido es de un 65%.

El coeficiente de GINI mide la desigualdad entre los valores de una distribución. Un coeficiente de Gini de cero expresa una igualdad perfecta, por otro lado, el coeficiente de Gini de 1 (100%) expresa la máxima desigualdad entre los valores.

## [1] 0.3328429

En nuestro caso vemos como el coeficiente de GINI expresa una desigualdad de 33%. Existe una relación entre el coeficiente de GINI y el AUC pero dado que en esta práctica nos hemos centrado en la precisión (ACC) no vamos a utilizar estos valores.

Ilustramos a continuación la importancia de las variables según el modelo XGB. Vemos como el término “gracias” destaca por sobre de las demás y como coinciden en la gran mayoría con la importancia vista en el modelo de Boosting.

4. Comparativa

Una vez ya hemos realizado la generación de los modelos en nuestro conjunto de Training y las predicciones en nuestro conjunto de Validación, compararemos los valores de precisión en la clasificación de los diferentes modelos estudiados.

##      MODELS    NAMES
## 8 0.6917626      GBM
## 3 0.6855624      LDA
## 7 0.6855624       RF
## 2 0.6842338   LOGREG
## 9 0.6789194      XGB
## 4 0.6607617      QDA
## 5 0.6430469     TREE
## 6 0.6430469    PRUNE
## 1 0.6196634 BASELINE

Obtenemos que el mejor modelo es Gradient Boosting. No hemos podido superar el 70% de precisión pero si lo comparamos con el modelo base (0.6196) obtenemos un margen de mejora de un 7%.

5. Modelo Final

A continuación aplicaremos el mejor modelo obtenido a un nuevo conjunto de Training formado por los antiguos conjuntos de Training y Validación y aplicaremos la predicción a un conjunto de Test que nuestros modelos aun no han visto.

El número de observaciones de nuestros nuevos conjuntos de Training y Test son los siguientes:

## [1] 9033   61
## [1] 2257   61

Podría suceder que al ampliar el conjunto de datos los valores óptimos que hemos calculado anteriormente para el modelo de Boosting ya no fuesen los mismos. Para ello aplicaremos Validación Cruzada con los mismos rangos de valores que los aplicados anteriormente para obtener la configuración óptima de parámetros.

Obtenemos que los parámetros óptimos son los siguientes:

##    n.trees interaction.depth shrinkage n.minobsinnode
## 54     200                10      0.05             20

El mejor valor de precisión obtenido a través de Validación Cruzada en el nuevo conjunto de Training es el siguiente:

## [1] 0.6857075

Finalmente, realizamos la predicción sobre el conjunto de Test.

## [1] 0.5888347

Sorprendentemente vemos que la estimación de la precisión ha bajado considerablemente incluso por debajo del modelo base.

Para intentar solucionar este valor tan bajo modificaremos los úmbrales de los parámetros del Grid para intentar encontrar un mejor modelo aumentando también el coste computacional. Nos fijamos que el número de árboles óptimo es de 200. Ampliaremos este valor a 400. El parámetro correspondiente al número mínimo de observaciones en un nodo para poder ser dividido también está en el límite. Ampliaremos esta valor a 40.

Obtenemos que los parámetros óptimos son los siguientes:

##    n.trees interaction.depth shrinkage n.minobsinnode
## 78     400                10       0.1             20

El mejor valor de precisión obtenido a través de Validación Cruzada en el nuevo conjunto de Training es el siguiente:

## [1] 0.6871461

Finalmente, realizamos la predicción sobre el conjunto de Test.

## [1] 0.5928223

Comprobamos a pesar de haber vuelto a ajustar con Validación Cruzada y con unos intervalos de valores mayores para los parámetros no obtenemos mejora.

6. Conclusiones

En esta práctica hemos comparado un total de 8 modelos de clasificación para obtener el que nos proporcionase mejores resultados de precisión sobre Tweets correctamente clasificados como positivos. Para ello hemo seguido los criterios de división del conjunto de datos en Training, Validación y Test y hemos aplicado Validación Cruzada para optimizar los parámetros de los modelos que lo requerían. Al comparar todos los modelos el que mejor resultados ha ofrecido ha sido Boosting.

A continuación hemos visto que para un conjunto de datos de Training de 9000 muestras el mejor modelo ha obtenido una precisión de un 68%, siendo un valor bastante aceptable. Pero cuando hemos utilizado las observaciones reservadas para Test el porcentaje de clasificación correcta ha descendido notablemente hasta un 58%. Un valor incluso menor que el del modelo base (62%). Ante estos resultados concluimos que a pesar de nuestros esfuerzos para encontrar un modelo óptimo, sería mejor clasificar los Tweets aleatoriamente que aplicando el mejor modelo obtenido.

Posiblemente las causas de este valor tan bajo en la predicción final sean las siguientes:

  • Una muestra de Tweets pequeña y un coeficiente de dispersión pequeño. Hay que considerar que un total de 9.000 Tweets de Training para el modelo final es un valor relativamente pequeño y que aplicando el coeficiente de dispersión del 1% sólo hemos conseguido un total de 60 términos que son las variables independientes que tienen que tener el poder significativo suficiente como para clasificar nuevos Tweets. Como hemos visto el poder significativo de estos términos no es suficiente.

  • La complejidad de modelar el lenguaje natural. Otro punto a considerar para dar una explicación a tan bajo resultado de precisión es la complejidad del lenguaje natural. En esta práctica solo hemos considerado los términos de manera independiente pero considerar unas características que pudiesen contemplar el poder significativo de la combinación de n-terminos (n-gramas) podría dar más significado a las variables y mayor influencia a la hora de predecir la polaridad de un Tweet. En este sentido, el tratamiento de las abreviaciones, los emojis, la detección de ironías, el análisis de la construcción sintáctica de las palabras, la consideración del valor semántico de los términos que forman un Tweet o una contextualización de los mensajes podría ayudar a obtener mejores resultados.

  • La subjetividad de la clasificación. Es importante destacar este aspecto ya que según se ha podido comprobar revisando el texto de algunos Tweets, éstos han sido clasificados de una manera muy subjetiva y por ejemplo Tweets que hablasen del Real Madrid o de Cristina Ronaldo eran clasificados como Positivos y otros que hablasen de Messi o del F.C. Barcelona eran considerados negativos. Estos aspectos también han podido influir en la correcta clasificación de nuestros modelos.

De todas maneras, indicar que según las fuentes consuladas (Sentiment Analysis) los porcentajes más elevados que se han obtenido utilizando muestras mayores y algoritmos más complejos como SVM han sido del 72%. Un porcentaje que si bien es elevado, aun dista de unos valores que nos permitan asegurar una modelización de la polaridad del lenguaje natural de una manera que nos permita unas ciertas garantías de acierto.

En cualquier caso, hemos desarrollado la comparativa de distintos modelos predictivos de clasificación, la estructura de la cual nos puede servir en futuros trabajos para obtener mejores resultados aportando nuevas características como los n-gramas que ayuden a obtener mayor significación a las variables.